#!/usr/bin/env python
# -*- coding: utf-8 -*-
# 文件名称: intervention_api.py
# 文件保存路径: backend/api/miniprogram/intervention_api.py
"""
微信小程序居家干预记录API
实现居家干预记录创建、图片上传、记录查询等功能
"""

from flask import request, jsonify, send_from_directory, current_app
from flask_jwt_extended import jwt_required, get_jwt_identity
from datetime import datetime, date
from sqlalchemy import desc
from backend.infrastructure.database import db
from backend.models.user import User
from backend.models.student import Student
from backend.models.intervention import InterventionRecord
from backend.api.miniprogram import miniprogram_bp
from backend.services.unified_log_service import UnifiedLogService
from backend.services.media_service import MediaService
from backend.config.config_manager import ConfigManager


def _validate_image_urls(raw_urls):
    """严格校验前端提交的图片 URL 列表（小程序居家干预专用）。
    设计目标：阻止任何“错误或脏”路径进入数据库（不做静默修正）。
    允许形式：/media/image/intervention/YYYY/MM/DD/<filename>
    规则：
      - raw_urls 必须是 list
      - 每个元素必须是 str 且非空
      - 不允许出现 '://'（拒绝绝对 URL 与协议）
      - 只能以 /media/image/intervention/ 开头
      - 不能包含第二个 '/media/image/' 片段
      - 不能以 '/' 结尾（避免目录化）
    任何一条违规则抛出 ValueError，消息包含首个违规原因。
    返回：原样列表（浅复制）
    """
    if raw_urls is None:
        return []
    if not isinstance(raw_urls, list):
        raise ValueError('image_urls 必须为数组(list)')
    validated = []
    for idx, u in enumerate(raw_urls):
        if not isinstance(u, str):
            raise ValueError(f'image_urls[{idx}] 非字符串')
        s = u.strip()
        if not s:
            raise ValueError(f'image_urls[{idx}] 为空')
        if '://' in s:
            raise ValueError(f'image_urls[{idx}] 不能是绝对URL')
        if not s.startswith('/media/image/intervention/'):
            raise ValueError(f'image_urls[{idx}] 必须以 /media/image/intervention/ 开头')
        if s.count('/media/image/') != 1:
            raise ValueError(f'image_urls[{idx}] 含有重复 /media/image/ 片段')
        if s.endswith('/'):
            raise ValueError(f'image_urls[{idx}] 末尾不允许 /')
        validated.append(s)
    return validated

# 创建统一日志服务实例
log_service = UnifiedLogService()

def _parse_frequency(frequency_str):
    """
    解析频次字符串，提取数字部分
    例：'3次/天' -> 3, '每天2次' -> 2, '5' -> 5
    """
    if not frequency_str:
        return None
    
    # 如果已经是数字，直接返回
    if isinstance(frequency_str, int):
        return frequency_str
    
    # 如果是字符串，尝试提取数字
    import re
    numbers = re.findall(r'\d+', str(frequency_str))
    if numbers:
        return int(numbers[0])  # 返回第一个找到的数字
    
    return None

@miniprogram_bp.route('/intervention/home', methods=['POST'])
@jwt_required()
def create_home_intervention():
    """
    创建居家干预记录
    """
    try:
        current_user_id = get_jwt_identity()
        # 使用 session.get 规避 deprecated Query.get (identity 为字符串)
        user = db.session.get(User, int(current_user_id))

        if not user or not user.student_id:
            return jsonify({'success': False, 'message': '用户未绑定学生'}), 400

        data = request.get_json()
        print(f"接收到的数据: {data}")  # 调试日志

        # 验证必要字段
        required_fields = ['intervention_date', 'intervention_type']
        for field in required_fields:
            if not data.get(field):
                return jsonify({'success': False, 'message': f'缺少必要字段: {field}'}), 400

        # 验证干预类型
        valid_types = ['耳穴压丸', '刮痧', '艾灸', '中药熏蒸', '热灸训练', '热磁脉冲', '拔罐']
        if data['intervention_type'] not in valid_types:
            return jsonify({'success': False, 'message': f'无效的干预类型: {data["intervention_type"]}'}), 400

        # 严格校验图片 URL（不做静默修正）
        try:
            image_urls = _validate_image_urls(data.get('image_urls'))
        except ValueError as ve:  # 用户提交不符合规范的 image_urls
            return jsonify({'success': False, 'message': '图片URL不合法', 'detail': str(ve)}), 400
        # 组装 operation_data
        operation_data = {}
        if image_urls:
            operation_data['image_urls'] = image_urls

        intervention = InterventionRecord(
            student_id=user.student_id,
            intervention_date=datetime.strptime(data['intervention_date'], '%Y-%m-%d').date(),
            intervention_type=data['intervention_type'],
            is_home_intervention=True,
            home_operator=data.get('operator_name'),
            home_operator_relation=data.get('operator_relation'),
            home_intervention_day=data.get('home_intervention_day'),
            daily_frequency=_parse_frequency(data.get('daily_frequency')),  # 解析频次
            parent_feedback=data.get('parent_feedback'),
            upload_source='小程序',
            child_cooperation=data.get('child_cooperation'),
            daily_effect_rating=data.get('daily_effect_rating'),
            details=data.get('notes'),  # 使用notes作为details
            data_year=str(datetime.now().year),
            operation_data=operation_data if operation_data else None
        )
        
        # 设置干预专用字段
        if data['intervention_type'] == '耳穴压丸':
            intervention.acupoints = data.get('acupoints')
            intervention.press_methods = data.get('press_methods')
            intervention.press_strength = data.get('press_strength', '中度')
            intervention.press_frequency = data.get('press_frequency')
        elif data['intervention_type'] == '刮痧':
            intervention.scraping_intensity = data.get('scraping_intensity')
            intervention.scraping_direction = data.get('scraping_direction')
            intervention.scraping_duration = data.get('scraping_duration')
            intervention.skin_reaction = data.get('skin_reaction')
        elif data['intervention_type'] == '艾灸':
            intervention.moxibustion_type = data.get('moxibustion_type')
            intervention.temperature_level = data.get('temperature_level')
            intervention.moxibustion_distance = data.get('moxibustion_distance')
        elif data['intervention_type'] == '中药熏蒸':
            intervention.steam_temperature = data.get('steam_temperature')
            intervention.medicine_formula = data.get('medicine_formula')
            intervention.steam_intensity = data.get('steam_intensity')
            intervention.comfort_level = data.get('comfort_level')
        elif data['intervention_type'] == '热灸训练':
            intervention.intensity_level = data.get('intensity_level')
            intervention.treatment_mode = data.get('treatment_mode')
            intervention.temperature_feedback = data.get('temperature_feedback')
            intervention.training_effect = data.get('training_effect')
        elif data['intervention_type'] == '热磁脉冲':
            intervention.pulse_frequency = data.get('pulse_frequency')
            intervention.magnetic_intensity = data.get('magnetic_intensity')
            intervention.pulse_pattern = data.get('pulse_pattern')
            intervention.sensation_feedback = data.get('sensation_feedback')
        elif data['intervention_type'] == '拔罐':
            intervention.suction_strength = data.get('suction_strength')
            intervention.cupping_method = data.get('cupping_method')
            intervention.skin_color_change = data.get('skin_color_change')
            intervention.cupping_marks = data.get('cupping_marks')
        
        db.session.add(intervention)
        db.session.commit()
        
        # 记录操作日志
        log_service.log_student_operation(
            student_id=user.student_id,
            action='CREATE', 
            operation_data={'intervention_type': intervention.intervention_type, 'date': intervention.intervention_date},
            operator=f'用户{user.id}',
            ip_address=request.remote_addr
        )
        
        return jsonify({
            'success': True,
            'data': {
                'id': intervention.id,
                'student_id': intervention.student_id,
                'intervention_date': intervention.intervention_date.isoformat(),
                'intervention_type': intervention.intervention_type,
                'is_home_intervention': intervention.is_home_intervention,
                'image_urls': image_urls or []
            },
            'message': '居家干预记录创建成功'
        })
        
    except Exception as e:
        print(f"创建干预记录异常: {str(e)}")  # 服务器端日志
        import traceback
        traceback.print_exc()  # 打印完整堆栈
        db.session.rollback()
        return jsonify({
            'success': False,
            'message': f'创建居家干预记录失败: {str(e)}'
        }), 500

@miniprogram_bp.route('/intervention/home', methods=['GET'])
@jwt_required()
def get_home_interventions():
    """
    获取居家干预记录列表
    """
    try:
        current_user_id = get_jwt_identity()
        user = db.session.get(User, int(current_user_id))
        if not user or not user.student_id:
            return jsonify({'success': False, 'message': '用户未绑定学生'}), 400
        
        # 获取查询参数
        page = request.args.get('page', 1, type=int)
        per_page = request.args.get('per_page', 10, type=int)
        intervention_type = request.args.get('intervention_type', type=str)
        
        # 构建查询 - 只查询居家干预记录
        query = InterventionRecord.query.filter_by(
            student_id=user.student_id,
            is_home_intervention=True
        )
        
        if intervention_type:
            query = query.filter(InterventionRecord.intervention_type == intervention_type)
        
        # 按干预日期倒序排列
        query = query.order_by(desc(InterventionRecord.intervention_date))
        
        # 分页
        pagination = query.paginate(
            page=page, 
            per_page=per_page, 
            error_out=False
        )
        
        records = []
        for record in pagination.items:
            # 尝试提取图片URL
            imgs = []
            try:
                if record.operation_data and isinstance(record.operation_data, dict):
                    raw_imgs = record.operation_data.get('image_urls') or []
                    if isinstance(raw_imgs, list):
                        # 数据已在写入前严格校验，直接使用
                        imgs = raw_imgs
            except Exception:
                imgs = []
            record_data = {
                'id': record.id,
                'student_id': record.student_id,
                'intervention_date': record.intervention_date.isoformat() if record.intervention_date else None,
                'intervention_type': record.intervention_type,
                'home_operator': record.home_operator,
                'home_operator_relation': record.home_operator_relation,
                'home_intervention_day': record.home_intervention_day,
                'daily_frequency': record.daily_frequency,
                'parent_feedback': record.parent_feedback,
                'child_cooperation': record.child_cooperation,
                'daily_effect_rating': record.daily_effect_rating,
                'details': record.details,
                'created_at': record.created_at.isoformat() if record.created_at else None,
                'image_urls': imgs
            }
            records.append(record_data)
        
        return jsonify({
            'success': True,
            'data': {
                'records': records,
                'pagination': {
                    'page': page,
                    'per_page': per_page,
                    'total': pagination.total,
                    'pages': pagination.pages,
                    'has_next': pagination.has_next,
                    'has_prev': pagination.has_prev
                }
            },
            'message': '获取居家干预记录成功'
        })
        
    except Exception as e:
        return jsonify({
            'success': False,
            'message': f'获取居家干预记录失败: {str(e)}'
        }), 500

@miniprogram_bp.route('/intervention/<int:record_id>', methods=['GET'])
@jwt_required()
def get_intervention_detail(record_id):
    """
    获取干预记录详情
    """
    try:
        current_user_id = get_jwt_identity()
        user = db.session.get(User, int(current_user_id))
        if not user or not user.student_id:
            return jsonify({'success': False, 'message': '用户未绑定学生'}), 400
        
        # 查询干预记录
        intervention = InterventionRecord.query.filter_by(
            id=record_id,
            student_id=user.student_id
        ).first()
        
        if not intervention:
            return jsonify({
                'success': False,
                'message': '干预记录不存在'
            }), 404
        
        # 构建详细数据
        # 提取可能存在的图片URL
        image_urls = []
        try:
            if intervention.operation_data and isinstance(intervention.operation_data, dict):
                raw_imgs = intervention.operation_data.get('image_urls') or []
                if isinstance(raw_imgs, list):
                    image_urls = raw_imgs
        except Exception:
            image_urls = []

        detail_data = {
            'id': intervention.id,
            'student_id': intervention.student_id,
            'intervention_date': intervention.intervention_date.isoformat() if intervention.intervention_date else None,
            'intervention_type': intervention.intervention_type,
            'is_home_intervention': intervention.is_home_intervention,
            'home_operator': intervention.home_operator,
            'home_operator_relation': intervention.home_operator_relation,
            'home_intervention_day': intervention.home_intervention_day,
            'daily_frequency': intervention.daily_frequency,
            'parent_feedback': intervention.parent_feedback,
            'child_cooperation': intervention.child_cooperation,
            'daily_effect_rating': intervention.daily_effect_rating,
            'details': intervention.details,
            'created_at': intervention.created_at.isoformat() if intervention.created_at else None,
            'upload_source': intervention.upload_source,
            'image_urls': image_urls
        }
        
        # 添加干预专用字段
        if intervention.intervention_type == '耳穴压丸':
            detail_data.update({
                'acupoints': intervention.acupoints,
                'press_methods': intervention.press_methods,
                'press_strength': intervention.press_strength,
                'press_frequency': intervention.press_frequency
            })
        elif intervention.intervention_type == '刮痧':
            detail_data.update({
                'scraping_intensity': intervention.scraping_intensity,
                'scraping_direction': intervention.scraping_direction,
                'scraping_duration': intervention.scraping_duration,
                'skin_reaction': intervention.skin_reaction
            })
        # ... 其他干预类型的专用字段
        
        return jsonify({
            'success': True,
            'data': detail_data,
            'message': '获取干预记录详情成功'
        })
        
    except Exception as e:
        return jsonify({
            'success': False,
            'message': f'获取干预记录详情失败: {str(e)}'
        }), 500

@miniprogram_bp.route('/intervention/upload_image', methods=['POST'])
@jwt_required()
def upload_intervention_image():
    """上传干预记录图片 (统一媒体规范 Stage1)
    返回相对URL: /media/image/intervention/YYYY/MM/DD/<filename>
    """
    try:
        current_user_id = get_jwt_identity()
        user = db.session.get(User, int(current_user_id))
        if not user:
            return jsonify({'success': False, 'message': '用户不存在'}), 404

        # 兼容字段名 image / file
        file_storage = None
        if 'image' in request.files:
            file_storage = request.files['image']
        elif 'file' in request.files:
            file_storage = request.files['file']
        else:
            return jsonify({'success': False, 'message': '没有上传的图片文件'}), 400

        if not file_storage or file_storage.filename.strip() == '':
            return jsonify({'success': False, 'message': '没有选择文件'}), 400

        # 使用 MediaService 保存
        relative_url, _physical = MediaService.save_image(file_storage, category='intervention')
        filename = relative_url.rsplit('/', 1)[-1]
        return jsonify({
                'success': True,
                'data': {
                    'image_url': relative_url,  # 仅相对路径
                    'filename': filename
                },
                'message': '图片上传成功'
            })
    except Exception as e:  # noqa: BLE001
        return jsonify({'success': False, 'message': f'图片上传失败: {str(e)}'}), 500

